/***************************************************************************\
 * The Mattise Kernel: Userland Software									*
 * Copyright 2007 Matthew Iselin											*
 * Licensed under the GPL													*
 *																			*
 * main.c																	*
 *																			*
 * Main message loop for the VFS											*
 *																			*
\***************************************************************************/

/***************************************************************************
 * Includes
 ***************************************************************************/
#include <stdio.h>
#include <process.h>
#include <mmsg.h>
#include <vfs.h>

/***************************************************************************
 * Globals
 ***************************************************************************/
 
// mount points
struct vfs_MountPoint mountPoints[1024];

// descriptors (old and useless now)
struct vfs_Descriptor descriptors[1024];

/***************************************************************************
 * Functions
 ***************************************************************************/

// handler for an open file
void fil_handler()
{
	// message size and message buffer
	int msize;
	char* mbuff;
	
	// already, we will have a message waiting (INITTHRD)
	struct RecvMsgData myMsg;
	while( 1 )
	{
		if( mattiseHasMessage() )
		{
			// get the message
			mbuff = mattiseRecvMessage( &myMsg );
			
			// done, break free of the loop
			break;
		}
	}
	
	// open it up and find out what the handler for all requests is
	struct vfs_Action* myAction = (struct vfs_Action*) mbuff;
	
	// get it
	int handlerpid = myAction->descriptor; // the other end of the hack
	
	// process with which we are working
	int myprocess = myAction->vfsArg3;
	
	// send the open message to it
	struct vfs_ReqData* request = (struct vfs_ReqData*) mattiseAllocMessageSz( sizeof( struct vfs_ReqData ) );
	request->msgcode = VFS_OPEN;
	request->descriptor = myprocess;
	request->datlen = sprintf( request->data, "%s", myAction->filenm );
	request->srcpid = myprocess;
	
	// free the buffer
	mattiseFreeMessage( mbuff );

	// send it out
	mattiseSendMessage( handlerpid, VFS_OPEN, (char*) request, sizeof( struct vfs_ReqData ) );
	
	// wait for the reply
	while( 1 )
	{
		if( mattiseHasMessage() )
		{
			// get the message
			mbuff = mattiseRecvMessage( &myMsg );
			
			// verify that we do in fact have to exit
			if( myMsg.msgcode == VFS_REPMSG )
				break;
		}
	}
	
	// take it in, get the internal descriptor
	struct vfs_ReqData* drvrep = (struct vfs_ReqData*) mbuff;
	int int_desc = drvrep->descriptor;
	
	// free the buffer
	mattiseFreeMessage( mbuff );

	// enter our message loop
	while( 1 )
	{
		if( mattiseHasMessage() )
		{
			// get the message
			mbuff = mattiseRecvMessage( &myMsg );
			
			// the request data
			struct vfs_ReqData* myRequest = (struct vfs_ReqData*) mbuff;
			struct vfs_ReqData* rep = (struct vfs_ReqData*) mattiseAllocMessageSz( sizeof( struct vfs_ReqData ) );
			
			// handle it
			if( myMsg.msgcode != VFS_CLOSE )
			{
				// forward the message onto the handler
				rep->descriptor = int_desc;
				mattiseSendMessage( handlerpid, myMsg.msgcode, (char*) rep, sizeof( struct vfs_ReqData ) );
			}
			else
			{
				// we're now done, so forward the message and quit
				// this is seperate because of the quit part
				
				// forward the message
				rep->descriptor = int_desc;
				mattiseSendMessage( handlerpid, VFS_CLOSE, (char*) rep, sizeof( struct vfs_ReqData ) );
				
				// we're done here, quit
				break;
			}
			
			// free the buffer
			mattiseFreeMessage( mbuff );
		}
	}
	while( 1 );
}

// Entry point
int main( int argc, char* argv[] )
{	
	// get the framebuffer
	__asm__ __volatile__ ( "int $0x80" : : "a" (34) );

	*((short*) 0xb8002) = (0x0a << 8) | 'f';

	// message data
	struct RecvMsgData myMsg;

	// wait for a message
	while( !mattiseHasMessage() );

	// get it
	char* mbuff = mattiseRecvMessage( &myMsg );
	if( !mbuff )
	{
		*((short*) 0xb8002) = (0x0b << 8) | 'f';
		while( 1 );
	}

	// free it
	mattiseFreeMessage( mbuff );

	// done!
	*((short*) 0xb8002) = (0x0a << 8) | 's';
	while( 1 );

	// index variable
	int i,j;
	
	// clear out the mount points
	for( i = 0; i < 1024; i++ )
		mountPoints[i].state = 0; // not available
	
	// are we running?
	int running = 1;
	
	// internal descriptor
	int mydesc;

	// valid, so we're set...
	*((short*) 0xb8002) = (0x07 << 8) | 'v';
	
	// main loop
	while( running )
	{
		if( mattiseHasMessage() )
		{
	// valid, so we're set...
	*((short*) 0xb8002) = (0x07 << 8) | '+';

			// get the message
			char* mbuff = mattiseRecvMessage( &myMsg );

	// valid, so we're set...
	*((short*) 0xb8002) = (0x07 << 8) | '_';

			// check that it's not null
			if( !mbuff )
				continue;
			
			// the request data
			struct vfs_ReqData* myRequest = (struct vfs_ReqData*) mbuff;
			struct vfs_Action* myAction = (struct vfs_Action*) mbuff;
			struct vfs_ReqData* myRequestRep = (struct vfs_ReqData*) mattiseAllocMessageSz( sizeof( struct vfs_ReqData ) );
			struct vfs_Action* myActionRep = (struct vfs_Action*) myRequestRep; // vfs_ReqData is bigger than vfs_Action

	// valid, so we're set...
	*((short*) 0xb8002) = (0x07 << 8) | 'f';
			
			// handle it...
			switch( myMsg.msgcode )
			{
				// SIGTERM: we're done
				case SIGTERM:
				
					// done with execution
					running = 0;
					break;
				
				// VFS_OPEN: opens a file
				case VFS_OPEN:

					{						
						// save the source pid
						int srcpid = myAction->vfsArg3;
						
						// last found location
						int lastfound = -1;
					
						// find a prefix (we search from the start, but don't break)
						// we don't break upon finding a match because something like
						// '/' would take over
						for( i = 0; i < 1024; i++ )
						{
							if( mountPoints[i].state )
							{
								// found a match in prefix?
								int found = !strncmp( myAction->filenm, mountPoints[i].prefix, mountPoints[i].preflen );
								
								// save the last found location
								if( found )
									lastfound = i;
							}
						}
						
						// could we find one?
						if( lastfound == -1 )
						{
							// return -1 as the descriptor
							struct vfs_ReqData* fail = (struct vfs_ReqData*) mattiseAllocMessageSz( sizeof( struct vfs_ReqData ) );
							fail->msgcode = myAction->msgcode;
							fail->datlen = -1;
							mattiseSendMessage( srcpid, myAction->msgcode, (char*) fail, sizeof( struct vfs_ReqData ) );
							
							// all done
							break;
						}
						
						// the descriptor to return
						int retdesc = -1;
						
						// create a new thread to handle this
						retdesc = createthread( (int) fil_handler, 2, myAction->filenm, 10 );
						
						// check for valid
						if( retdesc == -1 )
						{
							// return -1 as the descriptor
							struct vfs_ReqData* fail = (struct vfs_ReqData*) mattiseAllocMessageSz( sizeof( struct vfs_ReqData ) );
							fail->msgcode = myAction->msgcode;
							fail->datlen = -1;
							mattiseSendMessage( srcpid, myAction->msgcode, (char*) fail, sizeof( struct vfs_ReqData ) );
							
							// all done
							break;
						}
						
						// tell it the handler's PID, and some info about us
						memcpy( myActionRep, myAction, sizeof( struct vfs_Action ) );
						myActionRep->descriptor = mountPoints[lastfound].handler_pid; // this is a hack, by the way
						myActionRep->vfsArg3 = srcpid;
						mattiseSendMessage( retdesc, VFS_INITTHRD, (char*) myActionRep, sizeof( struct vfs_Action ) );
					}
					break;
				
				// VFS_*: does something with the file
				case VFS_READ:
				case VFS_WRITE:
				case VFS_SEEK:
				case VFS_GETC:
				case VFS_PUTC:
				case VFS_CLOSE:
				case VFS_STAT:
					
					// forward the message
					if( myRequest->descriptor == -1 )
					{
						myRequestRep->datlen = 0;
						mattiseSendMessage( myRequest->srcpid, myMsg.msgcode, (char*) myRequestRep, sizeof( struct vfs_ReqData ) );
					}
					else
					{
						mydesc = myRequest->descriptor;
						memcpy( myRequestRep, myRequest, sizeof( struct vfs_ReqData ) );
						mattiseSendMessage( mydesc, myMsg.msgcode, (char*) myRequestRep, sizeof( struct vfs_ReqData ) );
					}
					break;
				
				// VFS_MOUNT: mounts a filesystem
				case VFS_MOUNT:

					// find a spare mount point
					for( i = 0; i < 1024; i++ )
					{
						// check
						if( mountPoints[i].state == 0 )
						{
							// good to go
							break;
						}
					}

	// valid, so we're set...
	*((short*) 0xb8002) = (0x07 << 8) | 's';
					
					// valid mount point?
					if( 1 ) // testing atm... i == 1024 )
					{
						// return that it didn't work
						struct vfs_ReqData* fail = (struct vfs_ReqData*) myRequestRep; // mattiseAllocMessageSz( sizeof( struct vfs_ReqData ) );
						fail->msgcode = myAction->msgcode;
						fail->datlen = -1;
						mattiseSendMessage( myAction->vfsArg3, myAction->msgcode, (char*) fail, sizeof( struct vfs_ReqData ) );
						
						// all done
						break;
					}
					
					// add the mount point
					strcpy( mountPoints[i].prefix, myAction->filenm );
					mountPoints[i].preflen = myAction->nmlen;
					mountPoints[i].handler_pid = myAction->vfsArg3;
					mountPoints[i].state = 1;
					
					break;
				
				// VFS_UMOUNT: unmounts a filesystem
				case VFS_UMOUNT:
				
					// remove it (this is really easy)
					mountPoints[myAction->vfsArg3].state = 0;
					break;
			}
			
			// free the buffer
			mattiseFreeMessage( mbuff );
		}
	}
	while( 1 );
	
	// return success
	return 0;
}
